<template>
  <div :class="$options.name">
    <div class="base-form-content">
      <el-form
        ref="form"
        :size="size"
        :disabled="disabled"
        :label-width="labelWidth"
        v-bind="$attrs"
        @validate="validateMethod"
        @submit.prevent="() => {}"
      >
        <slot />
      </el-form>
    </div>
    <div class="base-form-actionbar">
      <!-- 后面统一这个 -->
      <slot name="actionbar" />
      <!-- 旧的不要用了 -->
      <slot name="footer">
      </slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'base-form',
  provide () {
    return {
      cols: this.cols
    }
  },
  props: {
    /**
     * 总列数
     */
    cols: {
      type: [Number, String],
      default: 2
    },
    disabled: {
      type: Boolean,
      default: false
    },
    size: {
      type: String,
      default: 'small'
    },
    /**
     * label宽度
     */
    labelWidth: {
      type: String,
      default: '100px'
    }
  },
  data () {
    return {
      resetValidate: false
    }
  },
  computed: {
    clearValidate () {
      return this.$refs.form.clearValidate
    },
    // 表单实例
    $form () {
      return this.$refs.form
    },
    // 字段实例
    $fields () {
      return (this.$form.fields || []) // .map($field => $field.$parent)
    },
    // 字段实例映射
    $fieldsCache () {
      return this.$fields.reduce((cache, $field) => {
        const { prop } = $field
        if (!cache[prop]) {
          cache[prop] = []
        }
        cache[prop] = $field
        return cache
      }, {})
    }
  },
  methods: {
    getScrollView (node) {
      if (!node) return null
      // 找到有滚动条的元素进行滚动
      const style = (node.style && (window.getComputedStyle ? window.getComputedStyle(node, '') : node.currentStyle)) || {}
      const overflowY = style.overflowY
      if (node.scrollHeight === node.offsetHeight || (overflowY !== 'auto' && overflowY !== 'scroll')) {
        return this.getScrollView(node.parentNode)
      }
      if (!node.parentNode) {
        return null
      }
      return node
    },
    validateMethod (prop, valid) {
      if (!valid && this.resetValidate) {
        const vnode = this.$fieldsCache[prop]
        // 表格中的item，找到表格滚动dom和单签item对应的row，将表格滚动到对应row位置
        let parent = vnode.$parent
        let node = parent.$el
        while (node && (!node.className || node.className.indexOf('el-table__row') === -1)) {
          node = node.parentNode
        }
        while (parent && parent.$options.name !== 'ElTable') {
          parent = parent.$parent
        }
        if (node && parent) {
          this.resetValidate && parent.$el.querySelector('.el-table__body-wrapper').scrollTo({
            top: node.offsetTop,
            behavior: 'smooth'
          })
        } else {
          // 普通表单滚动逻辑
          const scrollView = this.getScrollView(vnode.$el)
          if (scrollView) {
            this.resetValidate && vnode.$el.scrollIntoView({
              top: vnode.$el.offsetTop,
              behavior: 'smooth'
            })
          }
        }
        this.resetValidate = false
      }
    },
    validate (callback) {
      this.resetValidate = true
      let promise
      if (typeof callback !== 'function' && window.Promise) {
        promise = new Promise((resolve, reject) => {
          callback = function (valid) {
            valid ? resolve(valid) : reject(valid)
          }
        })
      }
      this.$refs.form.validate((valid, obj) => {
        callback && callback(valid, obj)
      })
      if (promise) {
        return promise
      }
      this.resetValidate = false
    },
    validateField (props, cb) {
      this.resetValidate = true
      this.$refs.form.validateField(props, valid => {
        cb && cb(valid)
      })
      this.resetValidate = false
    },
    resetFields () {
      this.$refs.form.resetFields()
    }
  }
}
</script>

<style lang="scss">
.base-form {
  height: 100%;
  display: flex;
  flex-flow: column;
  overflow: hidden;
  .base-form-content {
    height: calc(100% - 48px);
    overflow-y: auto;
    .el-form {
      padding: 10px;
      box-sizing: border-box;
      display: flex;
      flex-wrap: wrap;
    }
    .el-select,
    .el-input-number {
      width: 100%;
    }
  }
  .base-form-actionbar {
    width: 100%;
    min-height: 48px;
    display: flex;
    box-sizing: border-box;
    padding: 0 12px;
    align-items: center;
    justify-content: center;
    border-top: 1px solid #E8EAEC;
  }
}
</style>
